/**
 * 
 */
package ua.lviv.franko.matrix;

import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;

import ua.lviv.franko.matrix.hash.lu.HashMatrixLUStyle;
import ua.lviv.franko.matrix.hash.lu.LUFactorization;

/**
 * @author marko.bekhta
 * 
 */
public class SimpleLU {
	protected double[][]	L;
	protected double[][]	U;
	protected final int		N;

	public SimpleLU(double[][] matrix) {
		N = matrix.length;
		L = new double[N][N];
		U = new double[N][N];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				U[0][i] = matrix[0][i];
				L[i][0] = matrix[i][0] / U[0][0];
				double sum = 0;
				for (int k = 0; k < i; k++) {
					sum += L[i][k] * U[k][j];
				}
				U[i][j] = matrix[i][j] - sum;
				if (i > j) {
					L[j][i] = 0;
				} else {
					sum = 0;
					for (int k = 0; k < i; k++) {
						sum += L[j][k] * U[k][i];
					}
					L[j][i] = (matrix[j][i] - sum) / U[i][i];
				}
			}
		}
	}

	public double[] calculate(double[] b) {
		double[] y = new double[b.length];
		for (int i = 0; i < N; i++) {
			double sum = 0.0;
			for (int j = 0; j < i; j++) {
				sum += L[i][j] * y[j];
			}
			y[i] = (b[i] - sum);
		}

		double[] x = new double[N];

		for (int row = (N - 1); row >= 0; row--) {
			double sum = 0;
			for (int j = row; j < N; j++) {
				sum += U[row][j] * x[j];
			}
			x[row] = (y[row] - sum) / U[row][row];
		}

		return x;
	}
	
	public double[][] calculate(double[][] b) {
		double[][] y = new double[N][b[0].length];
		for (int i = 0; i < N; i++) {
			for (int k = 0; k < y[i].length; k++) {
				double sum = 0.0;
				for (int j = 0; j < i; j++) {
					sum += L[i][j] * y[j][k];
				}
				y[i][k] = (b[i][k] - sum);
			}
		}

		double[][] x = new double[N][b[0].length];

		for (int row = (N - 1); row >= 0; row--) {
			for (int k = 0; k < y[row].length; k++) {
				double sum = 0.0;
				for (int j = row; j < N; j++) {
					sum += U[row][j] * x[j][k];
				}
				x[row][k] = (y[row][k] - sum) / U[row][row];
			}
		}

		return x;
	}

	public static void main(String[] args) throws Exception {
		Locale.setDefault(Locale.US);
		System.out.println("Start of data reading");
		final int number = 3;
		Scanner scanner = new Scanner(new FileInputStream(new File("C:\\Users\\marko.bekhta\\Desktop\\matrixdata\\matrix2.txt")));
		double[][] matrix1 = new double[number][number];
		HashMatrixLUStyle matrix2 = new HashMatrixLUStyle(RowType.HASH_TYPE, number);
		for (int j = 0; j < number; j++) {
			for (int i = 0; i < number; i++) {
				double val = scanner.nextDouble();
				matrix1[i][j] = val;
				matrix2.setValue(i, j, val);
			}
		}

		System.out.println("Start of calcualtions");
		long start = System.nanoTime();
		LUFactorization luFactorization = new LUFactorization(matrix2);
		System.out.println("total time is = " + (System.nanoTime() - start));

		System.out.println("Start of calcualtions");
		start = System.nanoTime();
		SimpleLU lu = new SimpleLU(matrix1);
		System.out.println("total time is = " + (System.nanoTime() - start));
		
		double[][] b = {{6.0},{ 5.0},{ 5.0}};
		HashMatrixLUStyle.printMatrix(lu.calculate(b));
		
	}
}
